home *** CD-ROM | disk | FTP | other *** search
- /*
- Patch.c
-
- Base class Patch implementation. All patch classes follow the
- patching protocol set up by class Patch. TrapPatch and VectorPatch
- also implemented here.
-
- Part of PatchWorks, the Extension Development Framework.
-
- by Mouse Herrell & Patrick Beard.
-
- Permission is granted to use this source code for any purpose, as long
- as the copyright notice is maintained.
-
- © 1992 Berkeley Systems, Inc.
- */
-
- #include "LoMem2.h"
- #include "Exceptions.h"
- #include "Patch.h"
-
- #include <stdio.h>
- #include <Memory.h>
- #include <Errors.h>
- #include <OSUtils.h>
- #ifndef __GESTALTEQU__
- #include <GestaltEqu.h>
- #endif
-
- #ifdef THINK_C
- #if !__option(a4_globals)
- #define GetGlobals() GetA5()
- #else
- #define GetGlobals() GetA4()
- #endif
- #endif
-
- #ifdef applec
- #define GetGlobals() GetA5()
- #endif
-
- #ifdef __cplusplus
- extern "C" {
- #endif
- void PatchAgent(void);
- #ifdef __cplusplus
- }
- #endif
-
- #define cJsrAbsolute 0x4EB9
- #define cJmpAbsolute 0x4EF9
-
- Patch* Patch::theirList = nil;
-
- Patch::Patch()
- {
- itsNext = theirList; // put us at head of list.
- theirList = this;
-
- itsBehavior = nil; // no behaviour installed.
- itsGlobals = GetGlobals(); // value of our globals register.
- itsInstalled = false; // not installed yet.
- itsState = ePatchOn; // by default it is enabled.
-
- // allocate our patch stub.
- itsStub = (PatchStub*)NewPtr(sizeof(PatchStub));
- FailNil(itsStub);
-
- // fill in the patch stub.
- itsStub->itsJsrJmp = cJsrAbsolute; // absolute jsr instruction.
- itsStub->itsPatch = this; // pointer to ourself.
- }
-
- Patch::~Patch()
- {
- Patch** patch;
-
- // disable the patch so it can do no more damage.
- Disable();
-
- // remove us from the patch list.
- patch = &theirList;
- while (*patch && *patch != this)
- patch = &(**patch).itsNext;
- if (*patch)
- *patch = itsNext;
-
- // remove our glue code if we're not installed.
- if (itsStub && !itsInstalled)
- DisposePtr((Ptr)itsStub);
- }
-
- void Patch::Install()
- {
- itsStub->itsAgent = GetAgent(); // fill in the agent field.
- itsOld = Get(); // remember previous patch.
- Set(itsStub); // install new patch.
- itsInstalled = true; // note that we are in the patch chain.
- }
-
- void Patch::RemoveAll()
- {
- // remove all patches.
- Patch* patch = theirList;
- while (patch) {
- delete patch; // remove from duty.
- patch = patch->itsNext; // go to next patch.
- }
- }
-
- void Patch::Enable() { Switch(ePatchOn); }
- void Patch::Disable() { Switch(ePatchOff); }
-
- PatchState Patch::Switch(PatchState state)
- {
- PatchState oldState = itsState;
- itsState = state;
-
- // only change the internals of the stub if state is changing.
- if (state != oldState) {
- if (state == ePatchOn) {
- itsStub->itsJsrJmp = cJsrAbsolute;
- itsStub->itsAgent = GetAgent();
- } else {
- itsStub->itsJsrJmp = cJmpAbsolute;
- itsStub->itsAgent = itsOld;
- }
- // since we modified some code, flush the instruction & data caches.
- FlushDataCache();
- FlushInstructionCache();
- }
-
- return oldState;
- }
-
- void* Patch::operator new(size_t n)
- {
- void* p = NewPtrClear(n);
- if (!p) throw(memFullErr);
- return p;
- }
-
- void Patch::operator delete(void* p)
- {
- if (p) DisposPtr((Ptr)p);
- }
-
- PatchProcPtr Patch::Get()
- {
- throw (eAbstractErr);
- }
-
- void Patch::Set(PatchProcPtr proc)
- {
- throw (eAbstractErr);
- }
-
- PatchProcPtr Patch::GetAgent()
- {
- // universal agent. this could be replaced if needed, but probably won't be.
- return (PatchProcPtr)&PatchAgent;
- }
-
- void TrapPatch::InitTrapPatch(PatchProcPtr proc, short trap)
- {
- itsBehavior = proc;
- itsTrap = trap;
- }
-
- PatchProcPtr TrapPatch::Get()
- {
- return (PatchProcPtr)NGetTrapAddress(itsTrap, GetTrapType(itsTrap));
- }
-
- void TrapPatch::Set(PatchProcPtr proc)
- {
- NSetTrapAddress((long)proc, itsTrap, GetTrapType(itsTrap));
- }
-
- void VectorPatch::InitVectorPatch(PatchProcPtr proc, PatchVectorPtr vector)
- {
- itsBehavior = proc;
- itsVector = vector;
- }
-
- PatchProcPtr VectorPatch::Get()
- {
- return *itsVector;
- }
-
- void VectorPatch::Set(PatchProcPtr proc)
- {
- *itsVector = proc;
- }
-
- // Misc. utilities
-
- short theOldSR;
- VectorPatch* theAddressPatch;
- VectorPatch* theBusPatch;
-
- void PatchExceptions(void)
- {
- theOldSR = SetSR(cSupervisorState + InterruptMask(7));
-
- theAddressPatch = new VectorPatch;
- theAddressPatch->InitVectorPatch((PatchProcPtr)&VException, &JAddressError);
- theAddressPatch->Install();
-
- theBusPatch = new VectorPatch;
- theBusPatch->InitVectorPatch((PatchProcPtr)&VException, &JBusError);
- theBusPatch->Install();
- }
-
- void RestoreExceptions(void)
- {
- delete theAddressPatch;
- delete theBusPatch;
- SetSR(theOldSR);
- }
-
- void VException(ExceptionPatchFrame frame)
- {
- throw (1);
- }
-
- // routine to call an operating system trap, use frame->old directly to call toolbox routines.
-
- void CallOS(register PatchFrame* frame)
- {
- #ifdef THINK_C
- asm {
- movem.l frame->rd0, d0-d2/a0/a1 ; load up the registers.
- move.l frame->old, -(sp) ; call the os w/o using a register.
- rts
- movem.l d0-d2/a0/a1, frame->rd0 ; now we have the results.
- }
- #endif
- }
-